/* 
 * File:   main.cpp
 * Author: Tung Mai
 *
 * Created on April 2, 2010, 11:25 AM
 */

#include <assert.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>

using namespace std;

CFStringRef gCurrentConsoleUser;
FILE* file;
char buffer[512] = {0};

static CFStringRef CopyCurrentConsoleUsername(SCDynamicStoreRef store)
    // Returns the name of the current console user, or NULL if there is
    // none.  store may be NULL, in which case a transient dynamic store
    // session is used.
{
    CFStringRef result;

    result = SCDynamicStoreCopyConsoleUser(store, NULL, NULL);

    // If the current console user is "loginwindow", treat that as equivalent
    // to none.
    if ( (result != NULL) && CFEqual(result, CFSTR("loginwindow")) )
    {
        CFRelease(result);
        result = NULL;
    }

    return result;
}

static void MyNotificationProc(SCDynamicStoreRef store, CFArrayRef changedKeys, void* info)
    // Called out of our runloop when the current console user value
    // changes in the dynamic store.  It's possible to get multiple
    // redundant notifications, so we debounce the notification by checking
    // for changes relative to gCurrentConsoleUser.
{
    #pragma unused(changedKeys)
    #pragma unused(info)
    CFStringRef currentConsoleUser;
    Boolean didChange;
    char* userData = (char*) info;
    printf("user data is: %s\n", userData);
    
    // Get the current console user.
    currentConsoleUser = CopyCurrentConsoleUsername(store);
    // See if it changed.
    didChange = (gCurrentConsoleUser != NULL) != (currentConsoleUser != NULL);
//    if (!didChange && (gCurrentConsoleUser != NULL))
//    {
//        assert(currentConsoleUser != NULL); // because if it was NULL,
//                                            // didChange would already be true
//        didChange = ! CFEqual(gCurrentConsoleUser, currentConsoleUser);
//        printf("the same username\n");
//    }

    // If it did, log that fact and remember the current value.

    if (didChange)
    {
        if (gCurrentConsoleUser != NULL)
        {
            CFRelease(gCurrentConsoleUser);
        }
        gCurrentConsoleUser = currentConsoleUser;
        if (gCurrentConsoleUser != NULL)
        {
//            CFRetain(gCurrentConsoleUser);
            CFStringGetCString(gCurrentConsoleUser, buffer, 512, CFStringGetSystemEncoding());
        }
        else
        {
            sprintf(buffer, "No user logged in");
        }

        CFShow(gCurrentConsoleUser);
    }
}

int main(int argc, char **argv)
{
    #pragma unused(argc)
    #pragma unused(argv)
    Boolean             success;
    SCDynamicStoreRef   store;
    CFStringRef         key;
    CFArrayRef          keys;
    CFRunLoopSourceRef  rls;
    char *name = "Hello";
    SCDynamicStoreContext context = {0, name, NULL, NULL, NULL};
    
//    context.version = 0;
//    context.info = name;
//    context.retain = NULL;
//    context.release = NULL;
//    context.copyDescription = NULL;

    // Set up our connection to the dynamic store so that notifications are
    // delivered by calling MyNotificationProc.
    store = SCDynamicStoreCreate(NULL, CFSTR("com.apple.dts.ConsoleUser"), MyNotificationProc, &context);
    assert(store != NULL);

    // Set it up to notify us when the console user value changes.
    key = SCDynamicStoreKeyCreateConsoleUser(NULL);
    assert(key != NULL);

    keys = CFArrayCreate(NULL, (const void **) &key, 1, &kCFTypeArrayCallBacks);
    assert(keys != NULL);

    success = SCDynamicStoreSetNotificationKeys(store, keys, NULL);
    assert(success);

    // Add it to the runloop.
    rls = SCDynamicStoreCreateRunLoopSource(NULL, store, 0);
    assert(rls != NULL);

    CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);

    // Print the current value.
    gCurrentConsoleUser = CopyCurrentConsoleUsername(store);
    CFShow(gCurrentConsoleUser);

    // Run forever printing any changes.

    CFRunLoopRun();

    // Clean up code.  This simple tool will never execute this code
    // (because CFRunLoopRun will never return), but I've left it here
    // in case you adapt the code for a more complex situation.

    if (gCurrentConsoleUser != NULL) {
        CFRelease(gCurrentConsoleUser);
    }
    
    CFRunLoopSourceInvalidate(rls);
    CFRelease(rls);
    CFRelease(keys);
    CFRelease(key);
    CFRelease(store);

    return EXIT_SUCCESS;
}




//pascal OSStatus LogOnOffEventHandler(EventHandlerCallRef myHandler,
//                                              EventRef event,
//                                              void *userData)
//{
//    printf("Entered LogonOff callback\n");
//    OSStatus result = eventNotHandledErr;
//    FILE *myfile = (FILE *) userData;
//    if (GetEventClass(event) == kEventClassSystem)
//    {
////        FILE *myfile = NULL;
//
//        if (GetEventKind(event) == kEventSystemUserSessionActivated)
//        {
////            myfile = fopen("session.log", "w");
//            if (myfile)
//            {
//                fprintf(myfile, "System Log On");
//                fclose(myfile);
//            }
//        }
//        else if (GetEventKind(event) == kEventSystemUserSessionDeactivated)
//        {
////            myfile = fopen("session.log", "w");
//            if (myfile)
//            {
//                fprintf(myfile, "System Log Off");
//                fclose(myfile);
//            }
//        }
//        result = noErr;
//    }
//
//    return result;
//}
//
//int main(int argc, char** argv) {
//    FILE *myfile = fopen("logon.log", "w");
//    if (!myfile)
//    {
//        return 1;
//    }
//    fprintf(myfile, "Program Started\n");
////    fclose(myfile);
//
//    EventTypeSpec eventType[2];
//    EventHandlerUPP LogOnOffEventHandler;
//
//    eventType[0].eventClass = kEventClassSystem;
//    eventType[0].eventKind = kEventSystemUserSessionActivated;
//    eventType[1].eventClass = kEventClassSystem;
//    eventType[1].eventKind = kEventSystemUserSessionDeactivated;
//
//    LogOnOffEventHandler = NewEventHandlerUPP(LogOnOffEventHandler);
//    InstallApplicationEventHandler(LogOnOffEventHandler, 2, eventType, (void*) myfile, NULL);
//    RunApplicationEventLoop();
//
//    myfile = fopen("test.log", "a");
//    fprintf(myfile, "Program Finished.");
//    fclose(myfile);
//
//    return (EXIT_SUCCESS);
//}

